#include"Functie.h"
#include"funct.cpp"
#define nrOperatii 16

Functie::Functie(char *Expresie)
        {
            expresie = eliminaSpatiile(Expresie);

            radacina = creezArbore(0, strlen(expresie));
        }

Nod *Functie::creezArbore(int linf, int lsup)
{
    int i, pozMin, opMin, opNew;
    int nrP;
    Nod *rezultat = NULL;

    opMin = nrOperatii; pozMin = -1;
    nrP = 0;
    for (i = linf; i < lsup; i++)
    {
        opNew = nrP * nrOperatii;
        switch (expresie[i])
        {
            case '(': nrP++; opNew = opMin; break;
            case ')': nrP--; opNew = opMin; break;
            case '+': opNew++; opNew--; break;
            case '-': opNew += 1; break;
            case '*': opNew += 2; break;
            case '/': opNew += 3; break;
            case '^': opNew += 4; break;
            case 's': opNew = !strncmp(expresie + i, "sin", 3) ? opNew + 9: opMin; break;
            case 'c': if (!strncmp(expresie + i, "cos", 3)) opNew += 10;
                      else if (!strncmp(expresie + i, "ctg", 3)) opNew += 12;
                      else opNew = opMin; break;
            case 't': if (!strncmp(expresie + i, "tan", 3)) opNew += 11;
                      else opNew = opMin; break;
            case 'a': if (!strncmp(expresie + i, "asin", 4)) opNew += 5;
                      else if (!strncmp(expresie + i, "acos", 4)) opNew += 6;
                      else if (!strncmp(expresie + i, "atan", 4)) opNew += 7;
                      else if (!strncmp(expresie + i, "actg", 4)) opNew += 8;
                      else opNew = opMin; break;
            case 'l': if (!strncmp(expresie + i, "log", 3)) opNew += 13;
                      else if (!strncmp(expresie + i, "ln", 2)) opNew += 14;
                      else opNew = opMin; break;
            case 'e': if (!strncmp(expresie + i, "exp", 3)) opNew += 15;
                      else opNew = opMin; break;
            default: opNew = opMin;
        }
        verificPrecedenta(opNew, i, &opMin, &pozMin);
    }

    if (opMin < nrOperatii)
    {
        switch (opMin)
        {
            case 0: rezultat = new Plus(); break;
            case 1: rezultat = new Minus(); break;
            case 2: rezultat = new Inmultit(); break;
            case 3: rezultat = new Impartit(); break;
            case 4: rezultat = new Putere(); break;
            case 5: rezultat = new ASin(); break;
            case 6: rezultat = new ACos(); break;
            case 7: rezultat = new ATan(); break;
            case 8: rezultat = new ACtg(); break;
            case 9: rezultat = new Sin(); break;
            case 10: rezultat = new Cos(); break;
            case 11: rezultat = new Tangenta(); break;
            case 12: rezultat = new Cotan(); break;
            case 13: rezultat = new Logaritm(); break;
            case 14: rezultat = new LogaritmN(); break;
            case 15: rezultat = new Exp(); break;
        }
        if (opMin < 5)
        {
            rezultat->setFStang(creezArbore(linf, pozMin));
            rezultat->setFDrept(creezArbore(pozMin + 1, lsup));
        }
        else
        {
            int nrBeg, nrEnd = 1;
            for (nrBeg = 0; linf + nrBeg < strlen(expresie) && expresie[linf + nrBeg] != '('; nrBeg++)
                ;
            if (linf + nrBeg > strlen(expresie))
                nrEnd = nrBeg = 0;
            if (opMin == 13)
            {
                int pozMid;

                for (pozMid = nrBeg + 1; expresie[linf + pozMid] != ','; pozMid++)
                    ;
                rezultat->setFStang(creezArbore(linf + nrBeg + 1, linf + pozMid));
                rezultat->setFDrept(creezArbore(linf + pozMid + 1, lsup - nrEnd));
            }
            else
            {
                rezultat->setFStang(creezArbore(linf + nrBeg + 1, lsup - nrEnd));
                rezultat->setFDrept(NULL);
            }
        }
    }
    else
    {
        while (linf < lsup && expresie[linf] == ' ') linf++;
        while (lsup > linf && expresie[lsup - 1] == ' ') lsup--;
        if (expresie[linf] == '(')
        {
            while (expresie[linf] == '(')
            {
                linf++; lsup--;
            }
            return creezArbore(linf, lsup);
        }
        if (expresie[linf] == '-')
        {
            rezultat = new Inmultit();
            rezultat->setFStang(new Constanta(-1));
            rezultat->setFDrept(creezArbore(linf + 1, lsup));
        }
        if (expresie[linf] == 'x' && (lsup - linf == 1))
            rezultat = new Necunoscuta();
        else
        {
            char *aux = new char[lsup - linf + 1];
            int i;

            for (i = linf; i < lsup; i++)
                aux[i - linf] = expresie[i];
            aux[i - linf] = '\0';

            rezultat = new Constanta(atof(aux));

            delete aux;
            return rezultat;
        }
    }

    return rezultat;
}

void Functie::verificPrecedenta(int newPrec, int newPoz, int *oldPrec, int *oldPoz)
{
    if (newPrec < *oldPrec)
        {
            *oldPoz = newPoz;
            *oldPrec = newPrec;
        }
}

long double Functie::calculezValoare(long double x)
{
    radacina->setX(x);
    return radacina->calcul();
}

char *Functie::toString()
{
    return radacina->toString();
}

char *Functie::derivata()
{
    return radacina->derivare();
}

long double Functie::calculezDerivata(long double x)
{
    radacina->setX(x);
    return radacina->calculDerivata();
}

Functie::~Functie()
{
    delete radacina;
}


int Functie::fitY(long double rap, long double ymin, long double y, int limita)
{
    long double val = (y - ymin) / rap;
    if (val > limita) return 0;
    if (val < 0) return limita;
    return limita - ROUND(val) - 1;
}
